package com.swak.persistence;

import java.time.LocalDateTime;
import java.util.List;

import org.springframework.util.Assert;

import com.swak.App;
import com.swak.define.TableDefine;
import com.swak.define.TableDefines;
import com.swak.entity.IdEntity;
import com.swak.entity.Page;
import com.swak.entity.Parameters;
import com.swak.incrementer.IdGen;
import com.swak.utils.Lists;
import com.swak.utils.StringUtils;

import lombok.EqualsAndHashCode;
import lombok.ToString;

/**
 * 使用 AR 模式： 必须定义 _mapper， 是通过 _mapper 来代理运行的
 * 
 * @author lifeng
 * @date 2021年1月29日 下午4:01:22
 */
@SuppressWarnings({ "unchecked" })
public class Model<T, PK> extends IdEntity<T, PK> {

	@EqualsAndHashCode.Exclude
	@ToString.Exclude
	private transient BaseMapper<T, PK> _mapper;

	@EqualsAndHashCode.Exclude
	@ToString.Exclude
	private transient TableDefine<T> _table;

	@EqualsAndHashCode.Exclude
	@ToString.Exclude
	private transient Updative _updative;

	@EqualsAndHashCode.Exclude
	@ToString.Exclude
	private transient Selective _query;

	@EqualsAndHashCode.Exclude
	@ToString.Exclude
	private transient Parameters _param;

	@EqualsAndHashCode.Exclude
	@ToString.Exclude
	private transient List<T> _batch;

	@EqualsAndHashCode.Exclude
	@ToString.Exclude
	private transient int _limit;

	/**
	 * 最近一次操作影响的行数
	 */
	@EqualsAndHashCode.Exclude
	@ToString.Exclude
	private transient int _affectedRows;

	protected Updative newUpdative() {
		if (_updative == null) {
			_updative = Updative.of();
		}
		return _updative;
	}

	protected Selective newQuery() {
		if (_query == null) {
			_query = Selective.of();
		}
		return _query;
	}

	protected Parameters newParam() {
		if (_param == null) {
			_param = new Parameters();
		}
		return _param;
	}

	protected List<T> newBatch() {
		if (_batch == null) {
			_batch = Lists.newArrayList();
		}
		return _batch;
	}

	public T addBatch() {
		newBatch().add(as());
		return as();
	}

	public T addBatch(T e) {
		newBatch().add(e);
		return as();
	}

	public T addBatch(List<T> es) {
		newBatch().addAll(es);
		return as();
	}

	public T limit(int _limit) {
		this._limit = _limit;
		return as();
	}

	public T pageIndex(int pageIndex) {
		newParam().setPageIndex(pageIndex);
		return as();
	}

	public T pageSize(int pageSize) {
		newParam().setPageSize(pageSize);
		return as();
	}

	public T andIsNull(String property) {
		if (StringUtils.isNotBlank(property)) {
			newQuery().getCriteria().andIsNull(property);
		}
		return as();
	}

	public T andIsNotNull(String property) {
		if (StringUtils.isNotBlank(property)) {
			newQuery().getCriteria().andIsNotNull(property);
		}
		return as();
	}

	public T andConditionSql(String conditionSql) {
		if (StringUtils.isNotBlank(conditionSql)) {
			newQuery().getCriteria().andConditionSql(conditionSql);
		}
		return as();
	}

	public T andEqualTo(String property, Object value) {
		if (StringUtils.isNotBlank(property) && value != null) {
			newQuery().getCriteria().andEqualTo(property, value);
		}
		return as();
	}

	public T andNotEqualTo(String property, Object value) {
		if (StringUtils.isNotBlank(property) && value != null) {
			newQuery().getCriteria().andNotEqualTo(property, value);
		}
		return as();
	}

	public T andGreaterThan(String property, Object value) {
		if (StringUtils.isNotBlank(property) && value != null) {
			newQuery().getCriteria().andGreaterThan(property, value);
		}
		return as();
	}

	public T andGreaterThanOrEqualTo(String property, Object value) {
		if (StringUtils.isNotBlank(property) && value != null) {
			newQuery().getCriteria().andGreaterThanOrEqualTo(property, value);
		}
		return as();
	}

	public T andLessThan(String property, Object value) {
		if (StringUtils.isNotBlank(property) && value != null) {
			newQuery().getCriteria().andLessThan(property, value);
		}
		return as();
	}

	public T andLessThanOrEqualTo(String property, Object value) {
		if (StringUtils.isNotBlank(property) && value != null) {
			newQuery().getCriteria().andLessThanOrEqualTo(property, value);
		}
		return as();
	}

	public T andIn(String property, List<?> values) {
		if (StringUtils.isNotBlank(property) && values != null) {
			newQuery().getCriteria().andIn(property, values);
		}
		return as();
	}

	public T andNotIn(String property, List<?> values) {
		if (StringUtils.isNotBlank(property) && values != null) {
			newQuery().getCriteria().andNotIn(property, values);
		}
		return as();
	}

	public T andBetween(String property, Object value1, Object value2) {
		if (StringUtils.isNotBlank(property) && value1 != null && value2 != null) {
			newQuery().getCriteria().andBetween(property, value1, value2);
		}
		return as();
	}

	public T andNotBetween(String property, Object value1, Object value2) {
		if (StringUtils.isNotBlank(property) && value1 != null && value2 != null) {
			newQuery().getCriteria().andBetween(property, value1, value2);
		}
		return as();
	}

	public T andLike(String property, Object value) {
		if (StringUtils.isNotBlank(property) && value != null) {
			newQuery().getCriteria().andLike(property, value);
		}
		return as();
	}

	public T andLeftLike(String property, Object value) {
		if (StringUtils.isNotBlank(property) && value != null) {
			newQuery().getCriteria().andLeftLike(property, value);
		}
		return as();
	}

	public T andRightLike(String property, Object value) {
		if (StringUtils.isNotBlank(property) && value != null) {
			newQuery().getCriteria().andRightLike(property, value);
		}
		return as();
	}

	public T andNotLike(String property, Object value) {
		if (StringUtils.isNotBlank(property) && value != null) {
			newQuery().getCriteria().andNotLike(property, value);
		}
		return as();
	}

	public T andDateEqualTo(String property, LocalDateTime value) {
		if (StringUtils.isNotBlank(property) && value != null) {
			newQuery().getCriteria().andDateEqualTo(property, value);
		}
		return as();
	}

	public T andDateNotEqualTo(String property, LocalDateTime value) {
		if (StringUtils.isNotBlank(property) && value != null) {
			newQuery().getCriteria().andDateNotEqualTo(property, value);
		}
		return as();
	}

	public T andDateGreaterThan(String property, LocalDateTime value) {
		if (StringUtils.isNotBlank(property) && value != null) {
			newQuery().getCriteria().andDateGreaterThan(property, value);
		}
		return as();
	}

	public T andDateGreaterThanOrEqualTo(String property, LocalDateTime value) {
		if (StringUtils.isNotBlank(property) && value != null) {
			newQuery().getCriteria().andDateGreaterThanOrEqualTo(property, value);
		}
		return as();
	}

	public T andDateLessThan(String property, LocalDateTime value) {
		if (StringUtils.isNotBlank(property) && value != null) {
			newQuery().getCriteria().andDateLessThan(property, value);
		}
		return as();
	}

	public T andDateLessThanOrEqualTo(String property, LocalDateTime value) {
		if (StringUtils.isNotBlank(property) && value != null) {
			newQuery().getCriteria().andDateLessThanOrEqualTo(property, value);
		}
		return as();
	}

	public T andDateIn(String property, List<LocalDateTime> values) {
		if (StringUtils.isNotBlank(property) && values != null) {
			newQuery().getCriteria().andDateIn(property, values);
		}
		return as();
	}

	public T andDateNotIn(String property, List<LocalDateTime> values) {
		if (StringUtils.isNotBlank(property) && values != null) {
			newQuery().getCriteria().andDateNotIn(property, values);
		}
		return as();
	}

	public T andDateBetween(String property, LocalDateTime value1, LocalDateTime value2) {
		if (StringUtils.isNotBlank(property) && value1 != null && value2 != null) {
			newQuery().getCriteria().andDateBetween(property, value1, value2);
		}
		return as();
	}

	public T andDateNotBetween(String property, LocalDateTime value1, LocalDateTime value2) {
		if (StringUtils.isNotBlank(property) && value1 != null && value2 != null) {
			newQuery().getCriteria().andDateNotBetween(property, value1, value2);
		}
		return as();
	}

	public final T andIsNull(boolean condition, String property) {
		if (condition && StringUtils.isNotBlank(property)) {
			newQuery().getCriteria().andIsNull(property);
		}
		return as();
	}

	public final T andIsNotNull(boolean condition, String property) {
		if (condition && StringUtils.isNotBlank(property)) {
			newQuery().getCriteria().andIsNotNull(property);
		}
		return as();
	}

	public final T andConditionSql(boolean condition, String conditionSql) {
		if (condition && StringUtils.isNotBlank(conditionSql)) {
			newQuery().getCriteria().andConditionSql(conditionSql);
		}
		return as();
	}

	public final T andEqualTo(boolean condition, String property, Object value) {
		if (condition && StringUtils.isNotBlank(property) && value != null) {
			newQuery().getCriteria().andEqualTo(property, value);
		}
		return as();
	}

	public final T andNotEqualTo(boolean condition, String property, Object value) {
		if (condition && StringUtils.isNotBlank(property) && value != null) {
			newQuery().getCriteria().andNotEqualTo(property, value);
		}
		return as();
	}

	public final T andGreaterThan(boolean condition, String property, Object value) {
		if (condition && StringUtils.isNotBlank(property) && value != null) {
			newQuery().getCriteria().andGreaterThan(property, value);
		}
		return as();
	}

	public final T andGreaterThanOrEqualTo(boolean condition, String property, Object value) {
		if (condition && StringUtils.isNotBlank(property) && value != null) {
			newQuery().getCriteria().andGreaterThanOrEqualTo(property, value);
		}
		return as();
	}

	public final T andLessThan(boolean condition, String property, Object value) {
		if (condition && StringUtils.isNotBlank(property) && value != null) {
			newQuery().getCriteria().andLessThan(property, value);
		}
		return as();
	}

	public final T andLessThanOrEqualTo(boolean condition, String property, Object value) {
		if (condition && StringUtils.isNotBlank(property) && value != null) {
			newQuery().getCriteria().andLessThanOrEqualTo(property, value);
		}
		return as();
	}

	public final T andIn(boolean condition, String property, List<?> values) {
		if (condition && StringUtils.isNotBlank(property) && values != null) {
			newQuery().getCriteria().andIn(property, values);
		}
		return as();
	}

	public final T andNotIn(boolean condition, String property, List<?> values) {
		if (condition && StringUtils.isNotBlank(property) && values != null) {
			newQuery().getCriteria().andNotIn(property, values);
		}
		return as();
	}

	public final T andBetween(boolean condition, String property, Object value1, Object value2) {
		if (condition && StringUtils.isNotBlank(property) && value1 != null && value2 != null) {
			newQuery().getCriteria().andBetween(property, value1, value2);
		}
		return as();
	}

	public final T andNotBetween(boolean condition, String property, Object value1, Object value2) {
		if (condition && StringUtils.isNotBlank(property) && value1 != null && value2 != null) {
			newQuery().getCriteria().andBetween(property, value1, value2);
		}
		return as();
	}

	public final T andLike(boolean condition, String property, Object value) {
		if (condition && StringUtils.isNotBlank(property) && value != null) {
			newQuery().getCriteria().andLike(property, value);
		}
		return as();
	}

	public final T andLeftLike(boolean condition, String property, Object value) {
		if (condition && StringUtils.isNotBlank(property) && value != null) {
			newQuery().getCriteria().andLeftLike(property, value);
		}
		return as();
	}

	public final T andRightLike(boolean condition, String property, Object value) {
		if (condition && StringUtils.isNotBlank(property) && value != null) {
			newQuery().getCriteria().andRightLike(property, value);
		}
		return as();
	}

	public final T andNotLike(boolean condition, String property, Object value) {
		if (condition && StringUtils.isNotBlank(property) && value != null) {
			newQuery().getCriteria().andNotLike(property, value);
		}
		return as();
	}

	public final T andDateEqualTo(boolean condition, String property, LocalDateTime value) {
		if (condition && StringUtils.isNotBlank(property) && value != null) {
			newQuery().getCriteria().andDateEqualTo(property, value);
		}
		return as();
	}

	public final T andDateNotEqualTo(boolean condition, String property, LocalDateTime value) {
		if (condition && StringUtils.isNotBlank(property) && value != null) {
			newQuery().getCriteria().andDateNotEqualTo(property, value);
		}
		return as();
	}

	public final T andDateGreaterThan(boolean condition, String property, LocalDateTime value) {
		if (condition && StringUtils.isNotBlank(property) && value != null) {
			newQuery().getCriteria().andDateGreaterThan(property, value);
		}
		return as();
	}

	public final T andDateGreaterThanOrEqualTo(boolean condition, String property, LocalDateTime value) {
		if (condition && StringUtils.isNotBlank(property) && value != null) {
			newQuery().getCriteria().andDateGreaterThanOrEqualTo(property, value);
		}
		return as();
	}

	public final T andDateLessThan(boolean condition, String property, LocalDateTime value) {
		if (condition && StringUtils.isNotBlank(property) && value != null) {
			newQuery().getCriteria().andDateLessThan(property, value);
		}
		return as();
	}

	public final T andDateLessThanOrEqualTo(boolean condition, String property, LocalDateTime value) {
		if (condition && StringUtils.isNotBlank(property) && value != null) {
			newQuery().getCriteria().andDateLessThanOrEqualTo(property, value);
		}
		return as();
	}

	public final T andDateIn(boolean condition, String property, List<LocalDateTime> values) {
		if (condition && StringUtils.isNotBlank(property) && values != null) {
			newQuery().getCriteria().andDateIn(property, values);
		}
		return as();
	}

	public final T andDateNotIn(boolean condition, String property, List<LocalDateTime> values) {
		if (condition && StringUtils.isNotBlank(property) && values != null) {
			newQuery().getCriteria().andDateNotIn(property, values);
		}
		return as();
	}

	public final T andDateBetween(boolean condition, String property, LocalDateTime value1, LocalDateTime value2) {
		if (condition && StringUtils.isNotBlank(property) && value1 != null && value2 != null) {
			newQuery().getCriteria().andDateBetween(property, value1, value2);
		}
		return as();
	}

	public final T andDateNotBetween(boolean condition, String property, LocalDateTime value1, LocalDateTime value2) {
		if (condition && StringUtils.isNotBlank(property) && value1 != null && value2 != null) {
			newQuery().getCriteria().andDateNotBetween(property, value1, value2);
		}
		return as();
	}

	public T orderBy(String orderByClause) {
		if (StringUtils.isNotBlank(orderByClause)) {
			newQuery().setOrderByClause(orderByClause);
		}
		return as();
	}

	public T orderBy(OrderBy order) {
		if (order != null) {
			newQuery().setOrderByClause(order);
		}
		return as();
	}

	/**
	 * 查询时有用
	 * 
	 * @param column
	 * @return
	 */
	public T select(String column) {
		if (StringUtils.isNotBlank(column)) {
			newQuery().select(column);
		}
		return as();
	}

	/**
	 * updative 时有用
	 * 
	 * @param column
	 * @param value
	 * @return
	 */
	public T update(String column, Object value) {
		if (StringUtils.isNotBlank(column)) {
			newUpdative().update(column, value);
		}
		return as();
	}

	/**
	 * clearSelective、updative 时有用
	 * 
	 * @param column
	 * @return
	 */
	public T clear(String column) {
		if (StringUtils.isNotBlank(column)) {
			newUpdative().update(column);
		}
		return as();
	}

	// #################### 数据库操作 #############################

	public T get() {

		/*
		 * 走 GetSelective
		 */
		if (this.id != null && this._query != null && !Lists.isEmpty(this._query.columns)) {
			this._query.andEqualTo(Id, this.id);
			return this.getSqlRunner().getSelective(_query);
		}

		/*
		 * 走 getByCondition
		 */
		if (this.id != null && this._query != null) {
			this._query.andEqualTo(Id, this.id);
			return this.getSqlRunner().getByCondition(_query);
		}

		/*
		 * 走 Get 主键
		 */
		else if (this.id != null) {
			return this.getSqlRunner().get(id);
		}

		/*
		 * 走 GetSelective
		 */
		else if (this._query != null && !Lists.isEmpty(this._query.columns)) {
			return this.getSqlRunner().getSelective(_query);
		}

		/*
		 * 走 getByCondition
		 */
		else if (this._query != null) {
			return this.getSqlRunner().getByCondition(_query);
		}

		/*
		 * 走 GetUnique
		 */
		return this.getSqlRunner().getUnique(as());
	}

	public T save() {
		if (this.id == null) {
			return this.insert();
		}
		return this.update();
	}

	public T insert() {
		if (this._batch != null && this._batch.size() > 0) {
			this._affectedRows = this.batchInsert();
			return as();
		}
		this._affectedRows = this.getSqlRunner().insert(as());
		return as();
	}

	/**
	 * 插入: 有数据的字段才能插入到数据库否则走默认值;
	 * 
	 * @return
	 */
	public T insertive() {
		this._affectedRows = this.getSqlRunner().insertive(as());
		return as();
	}

	/**
	 * 插入: 有数据的字段才能插入到数据库否则走默认值;
	 * ignoreIfExists: 设置为 true, 如果数据已经存在会忽略;
	 * 
	 * @return
	 */
	public T insertive(boolean ignoreIfExists) {
		this._affectedRows = this.getSqlRunner().insertive(as(), ignoreIfExists);
		return as();
	}

	/**
	 * 注意：如果唯一索引中有 DelAt， replace、toggle、 stat 不起作用
	 * 
	 * @return
	 */
	@Deprecated
	public T replace() {
		this._affectedRows = this.getSqlRunner().replace(as());
		return as();
	}

	@Deprecated
	public T toggle() {
		this._affectedRows = this.getSqlRunner().toggle(as());
		return as();
	}

	public int batchInsert() {
		if (this._batch == null) {
			return 0;
		}
		return this.getSqlRunner().batchInsert(this._batch);
	}

	public int delete() {
		if (this._batch != null && this._batch.size() > 0) {
			this.batchDelete();
			return this._batch.size();
		} else if (this.id == null) {
			return this.deleteSelective();
		}
		return this.doDelete();
	}

	private int doDelete() {
		this.checkUpdateUseQueryConfition();
		return this.getSqlRunner().delete(as());
	}

	/**
	 * 删除数据(逻辑删除)：
	 * 
	 * UPDATE TEST_TABLE SET DEL_FALG = 1, DEL_AT = #{t.delAt} WHERE 1=1
	 * <if test="t.name != null">AND NAME = #{t.name}</if>
	 * 
	 * @return
	 */
	public int deleteSelective() {
		this.checkUpdateUseQueryConfition();
		return this.getSqlRunner().deleteSelective(as());
	}

	public int batchDelete() {
		if (this._batch == null) {
			return 0;
		}
		this.checkUpdateUseQueryConfition();
		return this.getSqlRunner().batchDelete(this._batch);
	}

	/**
	 * 通过主键修改所有的列;
	 * 
	 * @return
	 */
	public T update() {
		if (this._batch != null && this._batch.size() > 0) {
			this._affectedRows = this.batchUpdate();
		} else if (this.id == null) {
			this._affectedRows = this.updative();
		} else {
			this.doUpdate();
		}
		return as();
	}

	private void doUpdate() {
		this.checkUpdateUseQueryConfition();
		this._affectedRows = this.getSqlRunner().update(as());
	}

	/**
	 * 通过主键修改不为空的列：
	 * 
	 * UPDATE TEST_TABLE SET ${entity} 只修改不为空的列 WHERE ID = #{t.id};
	 * 
	 * @return
	 */
	public int updateSelective() {
		this.checkUpdateUseQueryConfition();
		return this.getSqlRunner().updateSelective(as());
	}

	/**
	 * 通过查询条件设置指定列的值：
	 * 
	 * UPDATE ${columns} 指定列设置值 FROM TEST_TABLE WHERE 1=1
	 * 条件表达式 : ${queryCondition} 或者 <if test="t.name != null">AND NAME = #{t.name}</if> 之一;
	 * 优先判断${queryCondition} 其次 属性的值;
	 * 
	 * use update(column, value), update(column) set ${columns} ;
	 * 
	 * 注意： Id 可以自动设置到查询中 version 会自动设置 _updative 中
	 * 
	 */
	public int updative() {
		if (this._query != null && this._query.isValid() && this.id != null) {
			this.andEqualTo(Id, this.id);
		} else if (this.id != null) {
			this._updative.selecteBy(as());
		}
		return this.getSqlRunner().updative(this._updative.selecteBy(_query).setVersion(version));
	}

	public int batchUpdate() {
		if (this._batch == null) {
			return 0;
		}
		this.checkUpdateUseQueryConfition();
		return this.getSqlRunner().batchUpdate(this._batch);
	}

//	/**
//	 * 清空选择的列: 已删除
//	 * UPDATE 
//	 * ${columns} 将指定的列设置为 null
//	 * FROM TEST_TABLE WHERE 1=1
//	 * ${queryCondition} 条件表达式
//	 * 
//	 * @return
//	 */
//	public int clearSelective() {
//		if (this.id != null) {
//			this.andEqualTo(Id, this.id);
//		}
//		return this.getSqlRunner().clearSelective(this._updative.selecteBy(_query).setVersion(version));
//	}

	public T lock() {
		return this.getSqlRunner().lock(id);
	}

	public boolean exists() {
		if (id != null) {
			return this.getSqlRunner().exists(id);
		}
		if (this._query != null) {
			return this.getSqlRunner().existsByCondition(this._query);
		}
		return this.getSqlRunner().existsSelective(as());
	}

	public List<T> query() {
		if (this._query != null && this._query.columns != null && this._limit > 0) {
			return this.getSqlRunner().querySelectiveByCondition(_query, this._limit);
		}
		if (this._query != null && this._query.columns != null) {
			return this.getSqlRunner().querySelectiveByCondition(_query);
		}
		if (this._query != null && this._limit > 0) {
			return this.getSqlRunner().queryByCondition(_query, this._limit);
		}
		if (this._query != null) {
			return this.getSqlRunner().queryByCondition(_query);
		}
		return this.getSqlRunner().querySelective(as());
	}

	public Integer count() {
		if (this._query != null) {
			return this.getSqlRunner().countByCondition(_query);
		}
		return this.getSqlRunner().countBySelective(as());
	}

	public Page<T> page() {
		if (_param == null) {
			_param = new Parameters();
		}
		if (this._query.columns != null) {
			return this.getSqlRunner().queryForSelectivePage(_query, _param);
		}
		return this.getSqlRunner().queryForPage(_query, _param);
	}

	public int updateOrInsertResult() {
		return this._affectedRows;
	}

	public T persist(boolean updateSelective) {
		if (IdGen.isInvalidId(this.getId())) {
			return this.insert();
		}
		if (updateSelective) {
			this.updateSelective();
		} else {
			this.update();
		}
		return as();
	}

	public T persist() {
		return this.persist(true);
	}

	@Deprecated
	public T statistic() {
		this.getSqlRunner().statistic(as());
		return as();
	}

	/**
	 * 执行Merge Sql, 替換之前的 statistic、 toggle、 replace
	 * 返回值说明：
	 * 0: 走 update 没有需要修改的列（通过查询没有查询到类或者需要修改的列和传递的参数的值一致） 
	 *    在这里是： 需要修改的列和传递的参数的值一致
	 * 1: 走 insert 没有发生主键或唯一键冲突， 此时 实体t 中的id值和数据库一致
	 * 1: 走 update 如果指定了主键，则会直接走update
	 * 2: 走 update 发生主键或唯一键冲突且实际上发生了修改, 这是id值和数据库不一致
	 * 
	 * -------
	 * 一般情况下返回值是： 1, 2； 因為必有需要修改的值，例如 updateDate
	 * -------
	 * 使用 ON DUPLICATE KEY 来执行数据的插入或更新（必须配置唯一索引使用）
	 * 增量添加 Stat:   (CASE WHEN %s IS NULL THEN 0 ELSE %s END) + #{t.value}
	 * 开关更新 Toggle: (CASE WHEN %s IS NULL OR %s = 0 THEN 1 ELSE 0 END)
	 * 
	 * ------
	 * 注意：默认会根据是否有主键判断是否需要执行insert；
	 * @param t
	 * @return 0, 1, 2
	 */
	public T merge() {
		this._affectedRows = this.getSqlRunner().merge(as());
		return as();
	}

	/**
	 * 执行Merge Sql, 替換之前的 statistic、 toggle、 replace
	 * 
	 * @param t
	 * @param insert 为true 强制走 insert 判断主键或者唯一键冲突后走 update;
	 */
	public T merge(boolean insert) {
		this._affectedRows = this.getSqlRunner().merge(as(), insert);
		return as();
	}

	// 注意：这个错误主要是提醒在使用update、delete时不用使用 QueryConfition
	// 防止误解
	protected void checkUpdateUseQueryConfition() {
		boolean useQuery = this._query != null && this._query.isValid();
		Assert.isTrue(!useQuery, "Please set delete or update condition in object field, do not use query confition!");
	}

	// #################### 基础模型 #############################

	protected BaseMapper<T, PK> getSqlRunner() {
		if (_mapper == null) {
			this._mapper = (BaseMapper<T, PK>) App.getBean(getTableDefine().getMapper());
		}
		return this._mapper;
	}

	protected TableDefine<T> getTableDefine() {
		if (this._table == null) {
			TableDefine<T> _table = (TableDefine<T>) TableDefines.lookup(this.getClass());
			if (_table == null) {
				throw new RuntimeException(String.format("Please define %sMapper that extends BaseMapper.",
						com.swak.utils.StringUtils.upperCaseFirstOne(this.getClass().getSimpleName())));
			}
			this._table = (TableDefine<T>) _table;
		}
		return this._table;
	}
}
